//
//  ChatViewController.swift
//  AESOLAR_IOS
//
//  Created by Mr.Wang on 2019/8/19.
//  Copyright © 2019 Mr.Wang. All rights reserved.
//

import UIKit
import RxSwift
import RxCocoa
import MJRefresh
import IQKeyboardManager
import RxDataSources
import TZImagePickerController
import YBImageBrowser

class ChatViewController: BaseUIViewController {
    
    let chatView = UIView()
    let textView = UITextField()
    let selectPhotoView = UIView()
    let tableView = UITableView.init(frame: .zero, style: .plain)
    let nodataView = NoDataView()
    var dataArray: [ChatSectionModel] = []
    let addImageButton = UIButton()
    var images: [String?] = []
    var page = 1
    let keyboardViewModel = KeyboardViewModel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = #colorLiteral(red: 0.9606800675, green: 0.9608443379, blue: 0.9606696963, alpha: 1)
        self.navigationItem.title = "留言板".localized
        
        APPMessage.shared.unreadMessageCount.accept(0)
        
        setupView()
        loadData()
        
        let header = MJRefreshNormalHeader.init(refreshingBlock: { [weak self] in
            self?.loadMoreData()
        })
        header.lastUpdatedTimeLabel?.isHidden = true
        header.stateLabel?.isHidden = true
        tableView.mj_header = header
        
        textView.rx.controlEvent(.editingDidBegin)
            .subscribe(onNext: { [weak self] (_) in
                self?.dismissSelectPhotoView()
            }).disposed(by: rx.disposeBag)
        
        keyboardViewModel.keyboardShow
            .subscribe(onNext: { [weak self] (height) in
                guard let self = self else { return }
                if self.tableView.contentSize.height - self.tableView.height - self.tableView.contentOffset.y < 20 ,
                    self.dataArray.count > 0 {
                    self.tableView.contentOffset = CGPoint(x: 0, y: self.tableView.contentSize.height - self.tableView.height + height)
                }
                self.selectPhotoView.snp.updateConstraints { (make) in
                    make.bottom.equalTo(-height)
                }
                self.view.layoutIfNeeded()
            }).disposed(by: rx.disposeBag)
        
        keyboardViewModel.keyboardDismiss
            .subscribe(onNext: { [weak self] (height) in
                guard let self = self else { return }
                self.selectPhotoView.snp.updateConstraints { (make) in
                    make.bottom.equalTo(-UIApplication.shared.bottomSafeDistance)
                }
                self.view.layoutIfNeeded()
            }).disposed(by: rx.disposeBag)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        IQKeyboardManager.shared().isEnabled = false
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillAppear(animated)
        IQKeyboardManager.shared().isEnabled = true
    }
    
    func loadData() {
        ApiManager.messageList(1).request()
            .dataModelMap(ChatListModel.self)
            .map{ $0.list }
            .map { [weak self] (data) -> [ChatSectionModel] in
                return self?.convert(list: data) ?? []
        }.subscribe(onNext: { [weak self] (sections) in
            guard let self = self else { return }
            self.dataArray = sections
            self.page = 2
            self.tableView.reloadData()
            guard sections.count > 0 else { return }
            self.tableView.scrollToRow(at: IndexPath.init(row: self.dataArray.count - 1, section: 0), at: .bottom, animated: false)
        }).disposed(by: rx.disposeBag)
    }
    
    func loadMoreData() {
        ApiManager.messageList(page).request()
            .dataModelMap(ChatListModel.self)
            .map{ $0.list }
            .map { [weak self] (data) -> [ChatSectionModel] in
                return self?.convert(list: data) ?? []
        }.subscribeOn(ConcurrentDispatchQueueScheduler.init(qos: .background))
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { [weak self] (sections) in
                guard let self = self else { return }
                self.tableView.mj_header?.endRefreshing()
                let orginCount = self.dataArray.count
                self.dataArray = sections + self.dataArray
                self.page += 1
                self.tableView.reloadData()
                guard sections.count > 0,
                    orginCount > 0 else {
                        return
                }
                self.tableView.scrollToRow(at: IndexPath.init(row: sections.count, section: 0), at: .top, animated: false)
                }, onError: { [weak self] _ in
                    self?.tableView.mj_header?.endRefreshing()
            }).disposed(by: rx.disposeBag)
    }
    
    func setupView() {
        selectPhotoView.config
            .clipsToBounds(true)
            .backgroundColor(.white)
            .addTo(view)
            .makeConstraints { (make) in
                make.left.right.equalToSuperview()
                make.bottom.equalTo(-UIApplication.shared.bottomSafeDistance)
                make.height.equalTo(0)
        }
        
        let photoButton = BottomTitleButton().config
            .image(UIImage.init(named: "chat_image"))
            .title("相册".localized)
            .font(UIFont.systemFont(ofSize: 12, weight: .medium))
            .titleColor(#colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1))
            .addTarget(self, action: #selector(selectFromPhoto))
            .addTo(selectPhotoView)
            .makeConstraints { (make) in
                make.left.equalTo(35)
                make.centerY.equalToSuperview()
                make.height.equalTo(60)
                make.width.equalTo(50)
        }.view
        
        BottomTitleButton().config
            .image(UIImage.init(named: "chat_camera"))
            .title("相机".localized)
            .font(UIFont.systemFont(ofSize: 12, weight: .medium))
            .titleColor(#colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1))
            .addTarget(self, action: #selector(takeImage))
            .addTo(selectPhotoView)
            .makeConstraints { (make) in
                make.left.equalTo(photoButton.snp.right).offset(35)
                make.centerY.equalToSuperview()
                make.height.equalTo(photoButton.snp.height)
                make.width.equalTo(photoButton.snp.width)
        }
        
        chatView.config
            .backgroundColor(.white)
            .addTo(view)
            .makeConstraints { (make) in
                make.left.right.equalToSuperview()
                make.bottom.equalTo(selectPhotoView.snp.top)
                make.height.equalTo(54)
        }
        
        UIView().config
            .backgroundColor(#colorLiteral(red: 0.9011778831, green: 0.9011778831, blue: 0.9011778831, alpha: 1))
            .addTo(chatView)
            .makeConstraints { (make) in
                make.left.top.right.equalToSuperview()
                make.height.equalTo(1)
        }
        
        let textBackground = UIView().config
            .backgroundColor(.white)
            .cornerRadius(17)
            .borderColor(UIColor.init(white: 0.95, alpha: 1))
            .borderWidth(0.9)
            .addTo(chatView)
            .makeConstraints { (make) in
                make.left.equalTo(10)
                make.right.equalTo(-50)
                make.height.equalTo(34)
                make.centerY.equalToSuperview()
        }.view
        
        textView.config
            .font(UIFont.systemFont(ofSize: 14, weight: .medium))
            .placeholder("输入您的问题...".localized)
            .delegate(self)
            .returnKeyType(.send)
            .enablesReturnKeyAutomatically(true)
            .addTo(textBackground)
            .makeConstraints { (make) in
                make.top.bottom.equalTo(0)
                make.left.equalTo(14)
                make.centerX.equalToSuperview()
        }
        
        addImageButton.config
            .image(UIImage.init(named: "chat_add"), for: .normal)
            .image(UIImage.init(named: "chat_close"), for: .selected)
            .addTarget(self, action: #selector(selectPhoto(_:)))
            .addTo(chatView)
            .makeConstraints { (make) in
                make.right.equalTo(-10)
                make.centerY.equalTo(textView.snp.centerY)
                make.height.width.equalTo(30)
        }
        
        tableView.tableHeaderView = UIView.init(frame: CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: 0.1))
        tableView.tableFooterView = UIView.init(frame: CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: 0.1))
        
        tableView.config
            .separatorStyle(.none)
            .backgroundColor(.clear)
            .register(MyChatCell.self)
            .register(OtherChatCell.self)
            .register(MyChatImageCell.self)
            .register(OtherChatImageCell.self)
            .estimatedRowHeight(0)
            .delegate(self)
            .dataSource(self)
            .keyboardDismissMode(.onDrag)
            .extra {
                $0.estimatedSectionHeaderHeight = 0
                $0.estimatedSectionFooterHeight = 0
        }.addTo(view)
            .makeConstraints { (make) in
                make.left.top.right.equalToSuperview()
                make.bottom.equalTo(chatView.snp.top)
        }
        tableView.addSubview(nodataView)
    }
    
    @objc func selectPhoto(_ button: UIButton) {
        button.isSelected = !button.isSelected
        self.view.endEditing(true)
        UIView.animate(withDuration: 0.2) { [unowned self] in
            if button.isSelected,
                self.tableView.contentSize.height - self.tableView.height - self.tableView.contentOffset.y < 20 ,
                self.dataArray.count > 0 {
                self.tableView.contentOffset = CGPoint(x: 0, y: self.tableView.contentSize.height - self.tableView.height + 120)
            }
            self.selectPhotoView.snp.updateConstraints { (make) in
                make.height.equalTo(button.isSelected ? 120 : 0)
            }
            self.view.layoutIfNeeded()
        }
    }
    
    func dismissSelectPhotoView() {
        addImageButton.isSelected = false
        UIView.animate(withDuration: 0.2) {
            self.selectPhotoView.snp.updateConstraints { (make) in
                make.height.equalTo(0)
            }
            self.view.layoutIfNeeded()
        }
    }
    
    @objc func selectFromPhoto() {
        let tz = TZImagePickerController()
        tz.modalPresentationStyle = .fullScreen
        tz.maxImagesCount = 1
        tz.showSelectBtn = false
        tz.navigationBar.barTintColor = APPConfig.baseColor
        tz.navigationBar.isTranslucent = false
        var locale = "en"
        if let userSelectLanguage = AppCache.shared.object(for: APPUserDefault.self).userSelectLanguage {
            switch userSelectLanguage {
            case .chinese:
                locale = "zh-Hans"
            case .english:
                locale = "en"
            case .de:
                locale = "en"
            case .vi:
                locale = "vi"
            }
        }
        tz.preferredLanguage = locale
        tz.allowTakeVideo = false
        tz.allowPickingVideo = false
        tz.pickerDelegate = self
        self.present(tz, animated: true, completion: nil)
    }
    
    @objc func takeImage() {
        PermissionProvider.request(.camera, success: { [weak self] in
            let photoPickerViewController = UIImagePickerController()
            photoPickerViewController.sourceType = .camera
            photoPickerViewController.delegate = self
            self?.present(photoPickerViewController, animated: true, completion: nil)
        }) { }
    }
    
    func sendMessage() {
        guard let text = textView.text,
            text.count > 0 else { return }
        
        ApiManager.sendMessage(content: text)
            .request()
            .trackingLoading()
            .filterCode200()
            .map{ _ -> ChatLayoutModel in
                let model = ChatModel.createWith(content: text)
                return ChatLayoutModel.layoutFrom(model)
        }.subscribe(onNext: { [weak self] (layout) in
            guard let self = self else { return }
            self.textView.text = ""
            self.insertLayout(model: ChatSectionModel.init(item: .myChat(layout), time: layout.model.createTime))
        }).disposed(by: rx.disposeBag)
    }
    
    func addImageMessage(_ image: UIImage) {
        let path = image.writeToFileName(name: String.random().md5() + ".png")
        
        UpLoadApimanager.uploadFile(URL.init(fileURLWithPath: path))
            .request()
            .dataModelMap(UploadModel.self)
            .map{ $0.id }
            .trackingLoading()
            .flatMap { (id) -> Observable<String> in
                return ApiManager.sendMessage(fileIds: [id])
                    .request()
                    .trackingLoading()
                    .filterCode200()
                    .map{ _ in id }
        }.map{ id -> ChatLayoutModel in
            let model = ChatModel.createWith(image: image, id: id)
            return ChatLayoutModel.layoutFrom(model)
        }.subscribeOn(ConcurrentDispatchQueueScheduler.init(qos: .background))
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { [weak self] (layout) in
                self?.insertLayout(model: ChatSectionModel.init(item: ChatItemModel.myImage(layout), time: layout.model.createTime))
            }).disposed(by: rx.disposeBag)
    }
    
    func insertLayout(model: ChatSectionModel) {
        self.dataArray.append(model)
        self.tableView.reloadData()
        self.tableView.scrollToRow(at: IndexPath.init(row: self.dataArray.count - 1, section: 0), at: .bottom, animated: true)
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
            guard let self = self else { return }
            self.loadData()
        }
    }
    
    func update(indexPath: IndexPath) {
        guard self.dataArray.count > indexPath.row else { return }
        let model = self.dataArray[indexPath.row].item.chatlayotModel.model
        let layout = ChatLayoutModel.layoutFrom(model)
        guard layout.model.ossList.first != nil else { return }
        switch model.type {
        case .my:
            self.dataArray[indexPath.row] = .init(item: .myImage(layout), time: model.createTime)
        case .other:
            self.dataArray[indexPath.row] = .init(item: .otherImage(layout), time: model.createTime)
        }
        self.tableView.reloadRows(at: [indexPath], with: .none)
    }
    
    func convert(list: [ChatModel]) -> [ChatSectionModel] {
        var lastList: [ChatModel] = []
        
        list.forEach { (model) in
            if model.content.count > 0 {
                var newModel = model
                newModel.ossList = []
                lastList.append(newModel)
            }
            if model.ossList.count > 0 {
                model.ossList.forEach { (oss) in
                    var newModel = model
                    newModel.content = ""
                    newModel.ossList = [oss]
                    lastList.append(newModel)
                }
            }
        }
        
        return lastList.map{ model -> ChatSectionModel in
            let layout = ChatLayoutModel.layoutFrom(model)
            let hasImage = model.ossList.first != nil
            switch (model.type, hasImage) {
            case (.my, false):
                return ChatSectionModel.init(item: .myChat(layout), time: model.createTime)
            case (.my, true):
                return ChatSectionModel.init(item: .myImage(layout), time: model.createTime)
            case (.other, false):
                return ChatSectionModel.init(item: .otherChat(layout), time: model.createTime)
            case (.other, true):
                return ChatSectionModel.init(item: .otherImage(layout), time: model.createTime)
            }
        }
    }
    
    func showImageFrom(_ index: Int) {
        let models = self.dataArray.map{ $0.item.chatlayotModel.model }
        self.images = models.map { $0.ossList.first?.id }
        let imageIds = images.compactMap{ $0 }
        
        guard let image = models[index].ossList.first?.id,
            let imageIndex = imageIds.firstIndex(of: image) else { return }
        
        let browser = YBImageBrowser.init()
        browser.toolViewHandlers = []
        browser.dataSource = self
        browser.currentPage = imageIndex
        browser.show()
    }
    
    override func navigationBarStyle() -> NavigationBarStyle {
        return .baseColor
    }
}

extension ChatViewController: UITableViewDelegate, UITableViewDataSource {
    
    func numberOfSections(in tableView: UITableView) -> Int {
        nodataView.isHidden = self.dataArray.count != 0
        return 1
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.dataArray.count
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return self.dataArray[indexPath.row].item.chatlayotModel.height
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let model = self.dataArray[indexPath.row]
        switch model.item {
        case .myChat(let model):
            let cell = tableView.dequeueReusableCell(MyChatCell.self)
            cell.bind(model)
            return cell
        case .myImage(let model):
            let cell = tableView.dequeueReusableCell(MyChatImageCell.self)
            cell.bind(model)
            cell.loadImageFinish = { [weak self] in
                self?.update(indexPath: indexPath)
            }
            cell.imageClickClosure = { [weak self] in
                self?.showImageFrom(indexPath.row)
            }
            return cell
        case .otherChat(let model):
            let cell = tableView.dequeueReusableCell(OtherChatCell.self)
            cell.bind(model)
            return cell
        case .otherImage(let model):
            let cell = tableView.dequeueReusableCell(OtherChatImageCell.self)
            cell.bind(model)
            cell.loadImageFinish = { [weak self] in
                self?.update(indexPath: indexPath)
            }
            cell.imageClickClosure = { [weak self] in
                self?.showImageFrom(indexPath.row)
            }
            return cell
        }
    }
    
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 0
    }
    
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        return UIView()
    }
    
    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return 0
    }
    
    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        return UIView()
    }
}

extension ChatViewController: UITextFieldDelegate {
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        self.sendMessage()
        return true
    }
    
}

extension ChatViewController: TZImagePickerControllerDelegate {
    
    func imagePickerController(_ picker: TZImagePickerController!, didFinishPickingPhotos photos: [UIImage], sourceAssets assets: [Any]!, isSelectOriginalPhoto: Bool) {
        guard let image = photos.first else { return }
        self.addImageMessage(image)
    }
    
}

extension ChatViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        guard let image = info[.originalImage] as? UIImage else {
            return
        }
        self.addImageMessage(image)
        picker.dismiss(animated: true, completion: nil)
    }
    
}

extension ChatViewController: YBImageBrowserDataSource {
    
    func yb_numberOfCells(in imageBrowser: YBImageBrowser) -> Int {
        return images.compactMap{$0}.count
    }
    
    func yb_imageBrowser(_ imageBrowser: YBImageBrowser, dataForCellAt index: Int) -> YBIBDataProtocol {
        let imageIds = images.compactMap{$0}
        let image = imageIds[index]
        
        let data = YBIBImageData()
        data.imageURL = URL.init(string: APPConfig.imagePath + image)
        
        guard let modelIndex = self.images.firstIndex(of: image) else { return data }
        
        if let cell = tableView.cellForRow(at: IndexPath.init(row: modelIndex, section: 0)) as? MyChatImageCell {
            data.projectiveView = cell.chatImageView
        } else if let cell = tableView.cellForRow(at: IndexPath.init(row: modelIndex, section: 0)) as? OtherChatImageCell {
            data.projectiveView = cell.chatImageView
        }
        
        return data
    }
    
}
